package utils

import (
	"net/http"
	"sync"
	"time"
	"io"
	"fmt"
	"net/url"
	"io/ioutil"
	"strings"
	"compress/gzip"
)

var (
	client httpClient
	once   sync.Once
)

var urlParse = url.Parse

type httpClient struct {
	client *http.Client
}

func (c httpClient) request(method, url string, body io.Reader) (*http.Request, error) {
	uri, err := urlParse(url)
	if err != nil {
		fmt.Println("无效url", url)
		return nil, err
	}
	req, err := http.NewRequest(method, url, body)
	if err != nil {
		fmt.Println("创建请求对象失败", err)
		return nil, err
	}
	req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8")
	req.Header.Set("Accept-Encoding", "gzip, deflate, br")
	req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
	req.Header.Set("Cache-Control", "max-age=0")
	req.Header.Set("Upgrade-Insecure-Requests", "1")
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36")
	req.Header.Set("Connection", "keep-alive")
	req.Header.Set("Host", uri.Host)
	return req, nil
}

func (c httpClient) Get(url string) ([]byte, error) {
	req, err := c.request("GET", url, nil)
	if err != nil {
		return nil, err
	}
	res, err := c.client.Do(req)
	if err != nil {
		fmt.Println("请求异常", err)
		return nil, err
	}
	defer res.Body.Close()
	var reader io.Reader = res.Body
	contentEncoding := strings.Join(res.Header["Content-Encoding"], ",")
	if strings.Contains(contentEncoding, "gzip") {
		reader, err = gzip.NewReader(reader)
		if err != nil {
			fmt.Println("处理gzip异常", err)
			return nil, err
		}
	}
	contentType := strings.Join(res.Header["Content-Type"], ",")
	headerCharset := false
	if strings.Contains(contentType, "gbk") {
		headerCharset = true
		reader = GB2312ToUTF8(reader)
	}
	buf, err := ioutil.ReadAll(reader)
	if err != nil {
		fmt.Println("读取请求内容异常")
		return nil, err
	}
	if !headerCharset {
		content := strings.ToLower(string(buf))
		if strings.Contains(content, "text/html; charset=gbk") || strings.Contains(content, "text/html;charset=gbk") {
			return GBKByteToUTF8Bype(buf)
		} else if strings.Contains(content, "text/html; charset=gb2312") || strings.Contains(content, "text/html;charset=gb2312") {
			return GB2312ByteToUTF8Byte(buf)
		}
	}
	return buf, nil
}

func (c httpClient) GetString(url string) (string, error) {
	buf, err := c.Get(url)
	return string(buf), err
}

func NewHttpClient() httpClient {
	once.Do(func() {
		client = httpClient{
			client: &http.Client{
				Timeout: time.Second * 10,
			},
		}
	})
	return client
}
